package se.perp.c4.control;

import java.awt.Rectangle;
import java.util.concurrent.CancellationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;
import se.perp.c4.control.iface.ICancellable;
import se.perp.c4.control.iface.IConnectionListener;
import se.perp.c4.net.Connection;
import se.perp.c4.ui.CancellableWaitDialog;
import se.perp.c4.ui.MainMenu;
import se.perp.c4.ui.MainWindow;

class ConnectionCreator implements ICancellable {

    private SwingWorker<Connection, Void> worker;
    private final CancellableWaitDialog waitDialog;
    private final IConnectionListener listener;
    private final MainMenu mainMenu;

    private ConnectionCreator(
            final MainWindow mw,
            final MainMenu mm,
            final String host,
            final int port,
            final IConnectionListener listener,
            final String msg,
            final boolean isStartingServer) {

        this.listener = listener;
        mainMenu = mm;
        int w = mw.getContainer().getWidth();
        int h = mw.getContainer().getHeight();

        waitDialog = new CancellableWaitDialog(
                mw, new Rectangle(0, 0, w, h), msg, "Connecting");
        waitDialog.setCancellableOperation(this);

        worker = new SwingWorker<Connection, Void>() {

            @Override
            protected Connection doInBackground() throws Exception {
                waitDialog.setVisible(true);
                if (isStartingServer) {
                    return Connection.newServer(port);
                } else {
                    return Connection.newClient(host, port);
                }
            }

            @Override
            protected void done() {
                try {
                    Connection conn = get();
                    waitDialog.dispose();
                    listener.gotConnection(conn);
                } catch (CancellationException ce) {
                    waitDialog.dispose();
                    reenableMenu();
                } catch (Exception e) {
                    Logger.getLogger(ConnectionCreator.class.getName()).log(
                            Level.SEVERE, e.getMessage(),e);
                    waitDialog.dispose();
                    reenableMenu();
                    if (isStartingServer) {
                        listener.clientConnectionFailed(port);
                    } else {
                        listener.serverConnectionFailed(host, port);
                    }
                }
            }
        };
        worker.execute();
    }

    private void reenableMenu() {
        mainMenu.setGameAsClientEnabled(true);
        mainMenu.setGameAsServerEnabled(true);
    }

    public void cancel() {
        worker.cancel(true);
        worker = null;
        reenableMenu();
    }

    public static void createServer(MainWindow mw, final MainMenu mm, int port, IConnectionListener listener) {
        String msg = "<html><body>Listening on port " + port + "...</body></html>";
        new ConnectionCreator(mw, mm, null, port, listener, msg, true);
    }

    public static void createClient(MainWindow mw, final MainMenu mm, String host, int port, IConnectionListener listener) {
        String msg = "<html><body>Trying to connect to<br>host " + host + " on port " + port + "...</body></html>";
        new ConnectionCreator(mw, mm, host, port, listener, msg, false);
    }
}
